package com.neborosoft.lib.stream;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import com.neborosoft.lib.utilities.Utilities;

import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.Map;


public final class Network {
    public static String getUrl(String url, Map<String, Object> params) throws IOException {
        StringBuilder urlBuilder = new StringBuilder();
        urlBuilder.append(url);

        if(!params.isEmpty()){
            urlBuilder.append("?");

            for(Map.Entry<String, Object> param : params.entrySet()){
                String key = URLEncoder.encode(param.getKey(),"UTF-8");
                String value = URLEncoder.encode(param.getValue().toString(),"UTF-8");

                urlBuilder.append(key);
                urlBuilder.append("=");
                urlBuilder.append(value);
                urlBuilder.append("&");
            }

            urlBuilder.deleteCharAt(urlBuilder.length() - 1);
        }

        return urlBuilder.toString();
    }

    public static String executeGetRequest(String url, Map<String, Object> params) throws IOException{
        url = getUrl(url, params);
        return executeRequestGET(url);
    }

    public static String executeRequestGET(String url) throws IOException {
        InputStream inputStream = null;
        try {
            URL urlObject = new URL(url);
            URLConnection connection = urlObject.openConnection();
            inputStream = connection.getInputStream();
            InputStreamReader responseReader = new InputStreamReader(inputStream);
            BufferedReader readBuffer = new BufferedReader(responseReader);
            StringBuilder resultString = new StringBuilder();
            String line;
            while ((line = readBuffer.readLine()) != null) {
                resultString.append(line);
            }
            readBuffer.close();
            return resultString.toString();
        } finally {
            if(inputStream != null){
                inputStream.close();
            }
        }
    }

    public static interface InterruptListener{
        boolean isInterrupted();
    }

    public static final byte[] getBytesFromStream(InputStream inputStream,
                                                  InterruptListener interruptListener,
                                                  ByteArrayOutputStream byteArrayOutputStream) throws IOException
    {
        try {
            byteArrayOutputStream.reset();
            final int maxReadCount = 1024;
            byte[] buf = new byte[maxReadCount];
            int readCount = 0;
            while (true) {
                if (interruptListener != null) {
                    if (interruptListener.isInterrupted()) {
                        throw new InterruptedIOException();
                    }
                }

                readCount = inputStream.read(buf);
                if (readCount < 0) {
                    break;
                }

                byteArrayOutputStream.write(buf, 0, readCount);
            }

            return byteArrayOutputStream.toByteArray();

        } catch (OutOfMemoryError e) {
            Utilities.logException(e);
            throw new InterruptedIOException();
        }
    }

    public static final byte[] getBytesFromStream(InputStream inputStream,
                                                  InterruptListener interruptListener) throws IOException
    {
        return getBytesFromStream(inputStream, interruptListener, new ReusableByteArrayOutputStream());
    }

    public static final byte[] getBytesFromStream(InputStream inputStream) throws IOException {
        return getBytesFromStream(inputStream, null);
    }

    public static final byte[] getBytesFromUrl(String url,
                                               InterruptListener interruptListener,
                                               ByteArrayOutputStream byteArrayOutputStream) throws IOException{
        InputStream inputStream = null;
        try {
            URL urlObject = new URL(url);
            URLConnection connection = urlObject.openConnection();
            inputStream = new BufferedInputStream(connection.getInputStream());

            if(byteArrayOutputStream != null) {
                return getBytesFromStream(inputStream, interruptListener, byteArrayOutputStream);
            } else {
                return getBytesFromStream(inputStream, interruptListener);
            }

        } finally {
            if(inputStream != null){
                inputStream.close();
            }
        }
    }

    public static final byte[] getBytesFromUrl(String url,
                                               InterruptListener interruptListener) throws IOException
    {
        return getBytesFromUrl(url, interruptListener, null);
    }

    public static final byte[] getBytesFromUrl(String url) throws IOException {
        return getBytesFromUrl(url, null);
    }

    public static Bitmap getBitmapFromUrl(String url,
                                          InterruptListener interruptListener,
                                          ByteArrayOutputStream byteArrayOutputStream) throws IOException
    {
        try {
            byte[] bytes = getBytesFromUrl(url, interruptListener, byteArrayOutputStream);
            return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
        }
        catch (OutOfMemoryError e){
            Utilities.logException(e);
            throw new InterruptedIOException();
        }
    }

    public static Bitmap getBitmapFromUrl(String url,
                                          InterruptListener interruptListener) throws IOException {
        return getBitmapFromUrl(url, interruptListener, null);
    }

    public static Bitmap getBitmapFromStream(InputStream inputStream) {
        return BitmapFactory.decodeStream(inputStream);
    }

    public static Bitmap getBitmapFromUrl(String url) throws IOException {
        InputStream inputStream = Stream.getInputStreamFromUrl(url);
        return getBitmapFromStream(inputStream);
    }
}
